package com.ccsoft.leetcode.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.ListIterator;

/**
 * 2021年11月10日 16:02:57 chanchaw
 * 计算器算法.
 * 2021年11月16日 13:51:59 测试 1+((2+3)*4)-5 通过
 * 没有制作检测非法运算符的功能，如果出现非法运算符程序会报异常
 */
@Service
public class Calculator {
    @Autowired
    private ReversePolishNotation reversePolishNotation;

    public BigDecimal cal(String notation){
        // 将计算表达式转为 LinkedList 类型，方便之后进行计算时频繁增删节点
        LinkedList<String> linkedList = reversePolishNotation.getPolishStack(notation);
        if( linkedList == null || linkedList.size()<=0 ) return BigDecimal.valueOf(0);

        LinkedList<String> ret = linkedList;
        do{
            ret = recursion(ret);
        }while(ret.size() > 1);

        return BigDecimal.valueOf(Long.parseLong(ret.getFirst()));
    }

    private LinkedList<String> recursion(LinkedList<String> linkedList){
        if( linkedList.size() == 1 ) return linkedList;
        ListIterator<String> iterator = linkedList.listIterator(linkedList.size());

        // 倒序遍历计算
        while(iterator.hasPrevious()){
            String element = iterator.previous();
            int currentIndex = linkedList.lastIndexOf(element);

            if( !reversePolishNotation.isOperator(element) ) continue;// 不是操作符则跳转到下一个元素

            BigDecimal mid = BigDecimal.valueOf(0);
            switch (element){
                case "+":
                    mid = BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+2))).add(BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+1))));
                    break;
                case "-":
                    mid = BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+2))).subtract(BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+1))));
                    break;
                case "*":
                    mid = BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+2))).multiply(BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+1))));
                    break;
                case "/":
                    mid = BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+2))).divide(BigDecimal.valueOf(Long.parseLong(linkedList.get(currentIndex+1))));
                    break;
            }

            linkedList.set(currentIndex + 2, mid.toString());
            linkedList.remove(currentIndex);
            linkedList.remove(currentIndex);
            return linkedList;
        }

        return linkedList;
    }
}
